﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core.Interfaces;
using Cofe.Core.Property;
using Cofe.Core.Service;

namespace Cofe.Core.EntryType
{
    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class EntryTypeInfoManager : IEntryTypeInfoManager
    {
        public static string Unknown_EntryType_Key = "Key_Unknown";

        #region Constructor

        #endregion

        #region Methods

        public string GetEntryTypeKey(IPropertyHost propertyHost)
        {
            if (propertyHost.Behaviors.IsPropertySupported(CofeProperties.Type))
                switch (propertyHost.Behaviors.GetProperty<string>(CofeProperties.Type))
                {
                    case "":
                    case EntryTypes.VolumeKey:
                    case EntryTypes.Container:
                    case EntryTypes.EntryType:
                    case EntryTypes.Link:
                        return null;
                }

            foreach (var eti in ServiceLocater.FindAllServices<IEntryTypeIdentifier>())
            {
                string key = eti.GetEntryTypeKey(propertyHost);
                if (key != null)
                    return key;
            }
            return Unknown_EntryType_Key;
        }


        public IPropertyProvider GetRootPropertyProvider(string rootKey)
        {
            List<PropertyPair> pps = new List<PropertyPair>();

            pps.Add(PropertyPair.FromValue(CofeProperties.Parent, null));
            pps.Add(PropertyPair.FromValue(CofeProperties.DefaultInterfaceType, typeof(ICofeDirectoryInfo)));
            pps.Add(PropertyPair.FromValue(CofeProperties.FullParseName, "{" + rootKey + "}"));
            pps.Add(PropertyPair.FromValue(CofeProperties.Type, EntryTypes.VolumeKey));
            pps.Add(PropertyPair.FromValue(CofeProperties.CofeAttributes, CofeAttributes.VirtualItems));
            Func<ParameterDic, IEnumerable<IPropertyProvider>> syncList = (pmDic) => { pmDic.IsHandled = true; return list(rootKey); };
            pps.Add(PropertyPair.FromValue(CofeDirectoryProperties.ListCore, syncList));
            return PropertyProvider.FromPropertyPairs(pps);
        }

        private IEnumerable<IPropertyProvider> list(string rootKey)
        {
            foreach (var entryTypeKey in CofeServices.EntryTypeInfoManager.KnownEntryTypeKey)
                yield return GetEntryTypeInfoPPAsync(rootKey, entryTypeKey).Result;
        }

        public async Task<IPropertyProvider> GetEntryTypeInfoPPAsync(string rootKey, string entryTypeKey)
        {
            lock (_entryTypeCache)
            {
                if (_entryTypeCache.ContainsKey(entryTypeKey))
                    return _entryTypeCache[entryTypeKey];
            }

            List<PropertyPair> retPPs = new List<PropertyPair>();

            foreach (var eti in ServiceLocater.FindAllServices<IEntryTypeInfoProvider>())
            {
                var etiPPs = await eti.GetEntryTypeInfoAsync(entryTypeKey);
                if (etiPPs != null)
                    retPPs.AddRange(etiPPs);
            }
            var pps = retPPs.Distinct(PropertyPairEqualityComparer.ComparePropertyOnly).ToList();

            pps.Add(PropertyPair.FromValue(CofeProperties.ParentPropertyProvider, GetRootPropertyProvider(rootKey)));
            pps.Add(PropertyPair.FromValue(CofeProperties.DefaultInterfaceType, typeof(IEntryTypeInfo)));
            pps.Add(PropertyPair.FromValue(CofeProperties.Label, String.Join(",", entryTypeKey)));
            pps.Add(PropertyPair.FromValue(CofeEntryTypeProperties.EntryTypeKey, entryTypeKey));
            pps.Add(PropertyPair.FromValue(CofeProperties.CofeAttributes, CofeAttributes.VirtualItems));
            pps.Add(PropertyPair.FromValue(CofeProperties.FullParseName, PathFE.Combine("{" + rootKey + "}", entryTypeKey)));
            pps.Add(PropertyPair.FromValue(CofeProperties.Type, EntryTypes.EntryType));
            pps.Add(PropertyPair.FromValue(CofeProperties.IsExists, true));

            var retVal = PropertyProvider.FromPropertyPairs(pps);

            lock (_entryTypeCache)
            {
                if (!(_entryTypeCache.ContainsKey(entryTypeKey)))
                    _entryTypeCache.Add(entryTypeKey, retVal);
            }

            return retVal;
        }


        #endregion

        #region Data

        private IServiceLocater _serviceLocater = null;
        private Dictionary<string, IPropertyProvider> _entryTypeCache = new Dictionary<string, IPropertyProvider>();

        #endregion

        #region Public Properties

        private IEntryConstructor EntryConstructor { get { return ServiceLocater.FindService<IEntryConstructor>(); } }
        public IEnumerable<string> KnownEntryTypeKey { get { return _entryTypeCache.Keys; } }
        public IServiceLocater ServiceLocater { get { return _serviceLocater ?? CofeServices.ServiceLocater; } set { _serviceLocater = value; } }

        #endregion








    }
}
